#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Predesys Server - Core - Service permissions management 
@version: 0.2.5
@license: GPL 3.0 (see "license" file)
@author: Jose A. Jimenez
@contact: jajimc@gmail.com"""

import sys
sys.dont_write_bytecode = True
import os
import os.path
DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.path.join(DIR, "../errorlog"))
import errorlog
import security
import coreexceptions
import sqlalchemy
import data
import users
import services

def get_permissions():
    """Gets all service permissions.
    @return: List of service permissions
    @rtype: C{list}"""
    permissions = []
    
    try:
        dbConnection = data.open_connection()
        statement = "select * from service_permissions;"
        result = data.execute(dbConnection, statement)
        for row in result:
            permissions.append([row["service_id"], row["user_group_id"]])
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.get_permissions")
        raise
    
    return permissions
    
def is_permission(serviceId, userGroupId):
    """Gets if two string correspond to a registered service permission.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @param userGroupId: User group ID
    @type userGroupId: C{str}
    @return: *True* if *serviceId* and *userGroupId* correspond to a registered service permission. *False* in other case.
    @rtype: C{bool}"""
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "": raise coreexceptions.ValueNotValidException("'serviceId' must be a valid string")
    if userGroupId == None or (type(userGroupId) != str and type(userGroupId) != unicode) or userGroupId == "": raise coreexceptions.ValueNotValidException("'userGroupId' must be a valid user ID")
    
    try:
        dbConnection = data.open_connection()
        statement = "select * from service_permissions where service_id='%s' and user_group_id='%s';" % (serviceId, userGroupId)
        result = data.execute(dbConnection, statement)
        row = result.fetchone()
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.is_permission")
        raise
    
    return (row != None)
    
def has_permissions_by_service(serviceId):
    """Gets if a service has at least one service permission.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @return: *True* if service has at least one service permission. *False* in other case.
    @rtype: C{bool}"""
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "": raise coreexceptions.ValueNotValidException("'serviceId' must be a valid string")
    
    try:
        dbConnection = data.open_connection()
        statement = "select * from service_permissions where service_id='%s';" % serviceId
        result = data.execute(dbConnection, statement)
        row = result.fetchone()
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.has_permissions_by_service")
        raise
    
    return (row != None)

def has_permissions_by_user_group(userGroupId):
    """Gets if a user group has at least one service permission.
    @param userGroupId: User group ID
    @type userGroupId: C{str}
    @return: *True* if user group has at least one service permission. *False* in other case.
    @rtype: C{bool}"""
    if userGroupId == None or (type(userGroupId) != str and type(userGroupId) != unicode) or userGroupId == "": raise coreexceptions.ValueNotValidException("'userGroupId' must be a valid string")
    
    try:
        dbConnection = data.open_connection()
        statement = "select * from service_permissions where user_group_id='%s';" % userGroupId
        result = data.execute(dbConnection, statement)
        row = result.fetchone()
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.has_permissions_by_user_group")
        raise
    
    return (row != None)
    
def get_service_user_groups(serviceId):
    """Gets all user groups associated by service permissions with a given service.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @return: List of user groups
    @rtype: C{list}"""
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "": raise coreexceptions.ValueNotValidException("'serviceId' must be a valid user ID")
    if not services.is_service(serviceId): raise coreexceptions.SystemException("'%s' is not a service" % serviceId)
    
    userGroups = []
    
    try:
        dbConnection = data.open_connection()
        statement = "select user_group_id from service_permissions where service_id='%s';" % serviceId
        result = data.execute(dbConnection, statement)
        for row in result:
            userGroups.append(row["user_group_id"])
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.get_service_user_groups")
        raise
    
    return userGroups
    
def get_user_group_services(userGroupId):
    """Gets all services associated by service permissions with a given user group.
    @param userGroupId: User group ID
    @type userGroupId: C{str}
    @return: List of services
    @rtype: C{list}"""
    if userGroupId == None or (type(userGroupId) != str and type(userGroupId) != unicode) or userGroupId == "": raise coreexceptions.ValueNotValidException("'userGroupId' must be a valid user ID")
    if not users.is_user_group(userGroupId): raise coreexceptions.SystemException("'%s' is not a user group" % userGroupId)
    
    services = []
    
    try:
        dbConnection = data.open_connection()
        statement = "select service_id from service_permissions where user_group_id='%s';" % userGroupId
        result = data.execute(dbConnection, statement)
        for row in result:
            services.append(row["service_id"])
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.get_user_group_services")
        raise
    
    return services
    
def add_permission(serviceId, userGroupId):
    """Adds a new service permission.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @param userGroupId: User group ID
    @type userGroupId: C{str}"""
    security.check_root()
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "" : raise coreexceptions.ValueNotValidException("'serviceId' must be a valid string")
    if userGroupId == None or (type(userGroupId) != str and type(userGroupId) != unicode) or userGroupId == "" : raise coreexceptions.ValueNotValidException("'userGroupId' must be a valid user ID")
    if not services.is_service(serviceId): raise coreexceptions.SystemException("'%s' is not a service" % serviceId)
    if not users.is_user_group(userGroupId): raise coreexceptions.SystemException("'%s' is not a user group" % userGroupId)
    if is_permission(serviceId, userGroupId): raise coreexceptions.SystemException("('%s', '%s') permission already exists" % (serviceId, userGroupId))
    
    try:
        dbConnection = data.open_connection()
        statement = "insert into service_permissions values ('%s', '%s');" % (serviceId, userGroupId)
        result = data.execute(dbConnection, statement);
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.add_permission")
        raise

def modify_permission(oldServiceId, oldUserGroupId, newServiceId, newUserGroupId):
    """Modifies an existing service permission.
    @param oldServiceId: Service permission old service ID
    @type oldServiceId: C{str}
    @param oldUserGroupId: Service permission old user group ID
    @type oldUserGroupId: C{str}
    @param newServiceId: Service permission new service ID
    @type newServiceId: C{str}
    @param newUserGroupId: Service permission new user group ID
    @type newUserGroupId: C{str}"""
    security.check_root()
    if oldServiceId == None or (type(oldServiceId) != str and type(oldServiceId) != unicode) or oldServiceId == "":
        raise coreexceptions.ValueNotValidException("'oldServiceId' must be a valid string")
    if oldUserGroupId == None or (type(oldUserGroupId) != str and type(oldUserGroupId) != unicode) or oldUserGroupId == "":
        raise coreexceptions.ValueNotValidException("'oldUserGroupId' must be a valid user ID")
    if newServiceId == None or (type(newServiceId) != str and type(newServiceId) != unicode) or newServiceId == "":
        raise coreexceptions.ValueNotValidException("'newServiceId' must be a valid string")
    if newUserGroupId == None or (type(newUserGroupId) != str and type(newUserGroupId) != unicode) or newUserGroupId == "":
        raise coreexceptions.ValueNotValidException("'newUserGroupId' must be a valid user ID")   
    if not is_permission(oldServiceId, oldUserGroupId): raise coreexceptions.SystemException("('%s', '%s') is not a permission" % (oldServiceId, oldUserGroupId))
    if oldServiceId != newServiceId and oldUserGroupId != newUserGroupId and is_permission(newServiceId, newUserGroupId):
        raise coreexceptions.SystemException("('%s', '%s') permission already exists" % (newServiceId, newUserGroupId))  
    if not services.is_service(newServiceId): raise coreexceptions.SystemException("'%s' is not a service" % newServiceId)
    if not users.is_user_group(newUserGroupId): raise coreexceptions.SystemException("'%s' is not a user group" % newUserGroupId)
    
    try:
        dbConnection = data.open_connection()
        statement = "update service_permissions set service_id='%s', user_group_id='%s' where service_id='%s' and user_group_id='%s';" % (newServiceId, newUserGroupId, oldServiceId, oldUserGroupId)
        result = data.execute(dbConnection, statement);
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.modify_permission")
        raise
    
def delete_permission(serviceId, userGroupId):
    """Deletes an existing service permission.
    @param serviceId: Service ID
    @type serviceId: C{str}
    @param userGroupId: User group ID
    @type userGroupId: C{str}"""
    security.check_root()
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "": raise coreexceptions.ValueNotValidException("'serviceId' must be a valid string")
    if userGroupId == None or (type(userGroupId) != str and type(userGroupId) != unicode) or userGroupId == "": raise coreexceptions.ValueNotValidException("'userGroupId' must be a valid user ID")
    if not is_permission(serviceId, userGroupId): raise coreexceptions.SystemException("('%s', '%s') is not a permission" % (serviceId, userGroupId))
    
    try:
        dbConnection = data.open_connection()
        statement = "delete from service_permissions where service_id='%s' and user_group_id='%s';" % (serviceId, userGroupId)
        result = data.execute(dbConnection, statement)
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.delete_permission")
        raise

def delete_permissions_by_service(serviceId):
    """Deletes all existing service permissions by a given service.
    @param serviceId: Service ID
    @type serviceId: C{str}"""
    security.check_root()
    if serviceId == None or (type(serviceId) != str and type(serviceId) != unicode) or serviceId == "" : raise coreexceptions.ValueNotValidException("'serviceId' must be a valid string")
    if not services.is_service(serviceId): raise coreexceptions.SystemException("'%s' is not a service" % serviceId)
    
    try:
        dbConnection = data.open_connection()
        statement = "delete from service_permissions where service_id='%s';" % serviceId
        result = data.execute(dbConnection, statement)
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.delete_permissions_by_service")
        raise

def delete_permissions_by_user_group(userGroupId):
    """Deletes all existing service permissions by a given user group.
    @param userGroupId: User group ID
    @type userGroupId: C{str}"""
    security.check_root()
    if userGroupId == None or (type(userGroupId) != str and type(userGroupId) != unicode) or userGroupId == "" : raise coreexceptions.ValueNotValidException("'userGroupId' must be a valid string")
    if not users.is_user_group(userGroupId): raise coreexceptions.SystemException("'%s' is not a user group" % userGroupId)
    
    try:
        dbConnection = data.open_connection()
        statement = "delete from service_permissions where user_group_id='%s';" % userGroupId
        result = data.execute(dbConnection, statement)
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.servicepermissions.delete_permissions_by_user_group")
        raise
